package user

import (
	"context"
	"net/http"
	"strings"
	"time"

	"github.com/google/uuid"
	"github.com/labstack/echo/v4"
	"github.com/rs/zerolog/log"
	"techoiceness.com/aiagent/llm-gateway/internal/entity"
	"techoiceness.com/aiagent/llm-gateway/internal/server/response"
	"techoiceness.com/aiagent/llm-gateway/internal/server/sse"
)

// CreateConversation 创建新对话并立即开始流式响应
func (h *UserHandler) CreateConversation(c echo.Context) error {
	user := c.Get("account").(*entity.User)

	var req CreateConversationRequest
	if err := c.Bind(&req); err != nil {
		return response.BadRequest(c, "请求格式错误")
	}

	// 验证请求参数
	if err := h.validator.Struct(&req); err != nil {
		return response.BadRequest(c, "请求参数验证失败: "+err.Error())
	}

	// 1. 创建对话（使用用户prompt作为默认标题）
	defaultTitle := req.Prompt
	if len(defaultTitle) > 50 {
		defaultTitle = defaultTitle[:50]
	}

	conversation := &entity.Conversation{
		UserID: user.ID,
		Title:  defaultTitle, // 使用用户prompt作为默认标题
	}

	if err := h.repos.GetConversation().CreateConversation(c.Request().Context(), conversation); err != nil {
		log.Error().
			Str("user_id", user.ID.String()).
			Msg("创建对话失败")
		return response.InternalServerError(c, "创建对话失败")
	}

	// 2. 生成对话轮次ID
	conversationRoundID := uuid.New()

	// 3. 创建用户消息
	userMessage := &entity.ClientMessage{
		ConversationID:      conversation.ID,
		UserID:              user.ID,
		Role:                "user",
		Content:             req.Prompt,
		Status:              entity.ClientMessageStatusCompleted,
		ConversationRoundID: conversationRoundID,
	}

	if err := h.repos.GetClientMessage().CreateClientMessage(c.Request().Context(), userMessage); err != nil {
		log.Error().
			Str("conversation_id", conversation.ID.String()).
			Str("user_id", user.ID.String()).
			Msg("创建用户消息失败")
		// 如果消息创建失败，删除已创建的会话
		h.repos.GetConversation().DeleteConversation(c.Request().Context(), conversation.ID)
		return response.InternalServerError(c, "创建用户消息失败")
	}

	// 4. 创建assistant消息（初始状态为pending）
	assistantMessage := &entity.ClientMessage{
		ConversationID:      conversation.ID,
		UserID:              user.ID,
		Role:                "assistant",
		Content:             "", // 初始为空，处理完成后更新
		Status:              entity.ClientMessageStatusPending,
		ConversationRoundID: conversationRoundID,
	}

	if err := h.repos.GetClientMessage().CreateClientMessage(c.Request().Context(), assistantMessage); err != nil {
		log.Error().
			Str("conversation_id", conversation.ID.String()).
			Str("user_id", user.ID.String()).
			Msg("创建助手消息失败")
		// 如果assistant消息创建失败，删除已创建的会话和用户消息
		h.repos.GetClientMessage().DeleteClientMessage(c.Request().Context(), userMessage.ID)
		h.repos.GetConversation().DeleteConversation(c.Request().Context(), conversation.ID)
		return response.InternalServerError(c, "创建助手消息失败")
	}

	// 5. 验证会话权限
	if err := h.validateConversationAccess(user.ID, conversation.ID.String()); err != nil {
		return response.Forbidden(c, "Access denied: "+err.Error())
	}

	// 6. 获取或创建agent
	agent := h.agentHub.GetOrCreateAgent(conversation.ID)
	if agent == nil {
		// 返回统一的错误响应格式
		errorResp := sse.NewChatResponse(conversation.ID, sse.StatusError).
			WithError("AGENT_ERROR", "无法创建或获取代理", "系统内部错误，请稍后重试", true)
		c.Response().Header().Set(echo.HeaderContentType, "application/json")
		c.Response().WriteHeader(http.StatusInternalServerError)
		errorJSON, _ := errorResp.ToJSON()
		return c.String(http.StatusInternalServerError, errorJSON)
	}

	// 7. 开始流式聊天
	streamResult, err := agent.ChatStream(c.Request().Context(), req.Prompt, conversationRoundID)
	if err != nil {
		// 如果流式聊天创建失败，更新assistant消息状态为错误
		assistantMessage.Status = entity.ClientMessageStatusFailed
		h.repos.GetClientMessage().UpdateClientMessage(c.Request().Context(), assistantMessage)

		log.Error().
			Str("conversation_id", conversation.ID.String()).
			Str("user_id", user.ID.String()).
			Msg("流式聊天启动失败")

		// 返回统一的错误响应格式
		errorResp := sse.NewChatResponse(conversation.ID, sse.StatusError).
			WithError("STREAM_ERROR", "流式聊天启动失败", err.Error(), true)
		c.Response().Header().Set(echo.HeaderContentType, "application/json")
		c.Response().WriteHeader(http.StatusInternalServerError)
		errorJSON, _ := errorResp.ToJSON()
		return c.String(http.StatusInternalServerError, errorJSON)
	}

	// 确保在handler退出时取消AI处理（如果还没完成）
	defer streamResult.Cancel()

	// 8. 设置SSE响应头
	sse.SetSSEHeaders(c)
	c.Response().WriteHeader(http.StatusOK)

	// 9. 创建消息转换器和拦截器
	converter := sse.NewChatResponseConverter(&sse.DefaultInterceptor{})

	// 10. 流式输出
	log.Info().
		Str("user_id", user.ID.String()).
		Str("conversation_id", conversation.ID.String()).
		Msg("开始流式响应")

	clientCtx := c.Request().Context()
	var userFacingContent strings.Builder // 只收集用户关心的内容
	var hasStreamedContent bool           // 标记是否已收集流式内容
	var tokensUsed int                    // 累计token使用量
	var modelName string                  // 使用的模型名称

streamLoop:
	for {
		select {
		case <-clientCtx.Done():
			// 客户端断开连接，但AI处理继续
			log.Warn().
				Str("user_id", user.ID.String()).
				Str("conversation_id", conversation.ID.String()).
				Msg("客户端断开连接，AI处理继续")
			return nil
		case output, ok := <-streamResult.MessageChan:
			if !ok {
				// 流式响应结束
				break streamLoop
			}

			// 只收集用户关心的AI回复内容
			switch output.Status {
			case sse.StatusStreaming:
				// 收集流式内容的增量部分
				if output.DeltaContent != "" {
					userFacingContent.WriteString(output.DeltaContent)
					hasStreamedContent = true
				}
			case sse.StatusCompleted:
				// 如果没有流式内容，则使用完整内容
				if !hasStreamedContent && output.Content != "" {
					userFacingContent.WriteString(output.Content)
				}
			case sse.StatusToolCalling:
				// 工具调用不收集到用户消息中，让AI处理工具调用
				// 工具调用的详情对用户不可见
				continue
			case sse.StatusError:
				// 错误状态不收集内容
				continue
			}

			// 注意：不收集ReasoningContent，因为用户通常不需要看到AI的推理过程

			// 通过转换器和拦截器处理消息
			streamEvent := converter.Convert(clientCtx, output)
			if err := sse.SendSSE(c.Response(), streamEvent); err != nil {
				log.Error().
					Str("user_id", user.ID.String()).
					Str("conversation_id", conversation.ID.String()).
					Str("error", err.Error()).
					Msg("发送SSE事件失败")
				return err
			}
		}
	}

	log.Info().
		Str("conversation_id", conversation.ID.String()).
		Msg("流式响应完成")

	// 10. 更新assistant消息状态
	userReply := userFacingContent.String()
	if userReply == "" {
		userReply = "AI处理完成，但无文本回复"
	}

	// 计算处理时间
	processingTime := time.Since(time.Unix(assistantMessage.CreatedAt.Unix(), 0)).Milliseconds()

	// 更新assistant消息为完成状态
	assistantMessage.Content = userReply
	assistantMessage.SetCompleted(processingTime, tokensUsed, modelName)

	if err := h.repos.GetClientMessage().UpdateClientMessage(c.Request().Context(), assistantMessage); err != nil {
		log.Error().
			Str("conversation_id", conversation.ID.String()).
			Str("assistant_message_id", assistantMessage.ID.String()).
			Str("error", err.Error()).
			Msg("更新助手消息失败")
	}

	log.Info().
		Str("user_id", user.ID.String()).
		Str("conversation_id", conversation.ID.String()).
		Int("content_length", len(userReply)).
		Int64("processing_time_ms", processingTime).
		Int("tokens_used", tokensUsed).
		Str("model", modelName).
		Msg("助手消息已更新")

	// 11. 发送结束信号
	if err := sse.SendSSEEnd(c.Response()); err != nil {
		log.Error().
			Str("conversation_id", conversation.ID.String()).
			Str("user_id", user.ID.String()).
			Str("error", err.Error()).
			Msg("发送结束信号失败")
	}

	// 12. 异步优化标题（不发送事件，避免连接已关闭的panic）
	go func() {
		ctx := context.Background()
		optimizedTitle, err := h.titleGenerator.GenerateTitleFromConversation(ctx, req.Prompt, userReply)
		if err != nil {
			log.Error().
				Str("user_id", user.ID.String()).
				Str("conversation_id", conversation.ID.String()).
				Err(err).Msg("优化对话标题失败")
			return
		}

		// 更新为优化后的标题
		conversation.Title = optimizedTitle
		if err := h.repos.GetConversation().UpdateConversation(ctx, conversation); err != nil {
			log.Error().
				Str("user_id", user.ID.String()).
				Str("conversation_id", conversation.ID.String()).
				Err(err).
				Msg("更新对话标题失败")
			// 注意：不再发送SSE事件，因为连接可能已关闭
			return
		}

		log.Info().
			Str("user_id", user.ID.String()).
			Str("conversation_id", conversation.ID.String()).
			Str("optimized_title", optimizedTitle).Msg("对话标题已优化")
	}()

	return nil
}

// GetConversations 获取用户的对话列表
func (h *UserHandler) GetConversations(c echo.Context) error {
	user := c.Get("account").(*entity.User)

	conversations, total, err := h.repos.GetConversation().GetConversationsByUserID(c.Request().Context(), user.ID, 0, 0)
	if err != nil {
		log.Error().
			Str("user_id", user.ID.String()).
			Err(err).
			Msg("获取用户对话列表失败")
		return response.InternalServerError(c, "failed to get conversations")
	}

	// 转换为响应格式
	rows := make([]ConversationRow, 0, len(conversations))
	for _, conv := range conversations {
		rows = append(rows, ConversationRow{
			ID:        conv.ID,
			Title:     conv.Title,
			UserID:    conv.UserID,
			CreatedAt: conv.CreatedAt.Unix(),
			UpdatedAt: conv.UpdatedAt.Unix(),
		})
	}

	responseData := GetConversationsResponse{
		Rows:  rows,
		Total: int(total),
	}

	return response.Success(c, responseData)
}

// DeleteConversation 删除对话
func (h *UserHandler) DeleteConversation(c echo.Context) error {
	user := c.Get("account").(*entity.User)
	reqDto := new(DeleteConversationRequest)
	if err := c.Bind(reqDto); err != nil {
		return response.BadRequest(c, "Invalid request format")
	}

	conversationID, err := uuid.Parse(reqDto.ID)
	if err != nil {
		return response.BadRequest(c, "Invalid conversation ID format")
	}

	// 检查对话是否属于当前用户
	hasAccess, err := h.repos.GetConversation().CheckConversationAccess(c.Request().Context(), conversationID, user.ID)
	if err != nil {
		log.Error().
			Str("user_id", user.ID.String()).
			Err(err).
			Msg("对话检查时数据库错误")
		return response.InternalServerError(c, "internal server error")
	}
	if !hasAccess {
		return response.NotFound(c, "conversation not found")
	}

	// 删除对话（这将级联删除相关的消息）
	if err := h.repos.GetConversation().DeleteConversation(c.Request().Context(), conversationID); err != nil {
		log.Error().
			Str("user_id", user.ID.String()).
			Str("conversation_id", conversationID.String()).
			Err(err).
			Msg("删除对话失败")
		return response.InternalServerError(c, "failed to delete conversation")
	}

	log.Info().
		Str("user_id", user.ID.String()).
		Str("conversation_id", conversationID.String()).
		Msg("用户删除对话")

	return response.Success(c, map[string]string{
		"message": "conversation deleted successfully",
	})
}

// GetConversationMessages 获取对话的消息列表
func (h *UserHandler) GetConversationMessages(c echo.Context) error {
	user := c.Get("account").(*entity.User)

	reqDto := new(GetConversationMessagesRequest)
	if err := c.Bind(reqDto); err != nil {
		return response.BadRequest(c, "Invalid request format")
	}
	conversationID, err := uuid.Parse(reqDto.ID)
	if err != nil {
		return response.BadRequest(c, "Invalid conversation ID format")
	}

	// 检查对话是否属于当前用户
	hasAccess, err := h.repos.GetConversation().CheckConversationAccess(c.Request().Context(), conversationID, user.ID)
	if err != nil {
		log.Error().
			Str("user_id", user.ID.String()).
			Err(err).
			Msg("对话检查时数据库错误")
		return response.InternalServerError(c, "internal server error")
	}
	if !hasAccess {
		return response.NotFound(c, "conversation not found")
	}

	// 获取客户端消息列表
	clientMessages, err := h.repos.GetClientMessage().GetClientMessageHistory(c.Request().Context(), conversationID, 0, 0)
	if err != nil {
		log.Error().
			Str("user_id", user.ID.String()).
			Str("conversation_id", conversationID.String()).
			Err(err).
			Msg("获取对话消息失败")
		return response.InternalServerError(c, "获取对话消息失败")
	}

	// 转换为响应格式
	rows := make([]MessageRow, 0, len(clientMessages))
	for _, msg := range clientMessages {
		row := MessageRow{
			ID:             msg.ID,
			ConversationID: msg.ConversationID,
			Role:           msg.Role,
			Content:        msg.Content,
			Status:         string(msg.Status),
			CreatedAt:      msg.CreatedAt.Unix(),
		}

		// 添加assistant消息的元数据
		if msg.Role == "assistant" {
			if msg.ProcessingTime > 0 {
				row.ProcessingTime = msg.ProcessingTime
			}
			if msg.Model != "" {
				row.Model = msg.Model
			}
			if msg.TokensUsed > 0 {
				row.TokensUsed = msg.TokensUsed
			}
			if msg.ErrorMessage != "" {
				row.ErrorMessage = msg.ErrorMessage
			}
		}

		rows = append(rows, row)
	}

	responseData := GetConversationMessagesResponse{
		Rows:  rows,
		Total: len(rows),
	}

	return response.Success(c, responseData)
}
